using System;
using System.Drawing;
using System.Reflection;
using System.Windows.Forms;
using System.Collections.Generic;
using rlTodayMakeSkin.GUI;
using rlTodayMakeSkin.Project;
using rlTodayMakeSkin.Project.XmlElement;
using rlTodayMakeSkin.Project.XmlElement.Properties;

namespace rlTodayMakeSkin.GUI
{
    /// <summary>
    /// contains currently selected controls in the display. It's implemented as a Singleton
    /// </summary>
    public class SelectedControlsManager
    {
        private List<XmlElementPropertiesList> controls = new List<XmlElementPropertiesList>();
        //private SelectedControlsManager man = new SelectedControlsManager();
        private bool moving = false;
        private int intDownX = 0;
        private int intDownY = 0;

        public delegate void ChangedPropertyEvent(SkinControl sender, XmlElementProperty newValue);
        public delegate void ChangedSelectionEvent(XmlElementPropertiesList list);

        public static event ChangedPropertyEvent ChangedProperty;
        public static event ChangedSelectionEvent ChangedSelection;

        private static SelectedControlsManager man;
        private static PropertiesWindow propWindow;
        private static ISkinDisplay display;

        //PRIVATE CONSTRUCTOR
        private SelectedControlsManager(){}

        /// <summary>
        /// Initializes the manager.
        /// </summary>
        /// <param name="pw">an istance of PropertiesWindow class</param>
        /// <remarks>This method must be called before of each other method call.</remarks>
        public static void initManager(PropertiesWindow propWin)
        {
            man = new SelectedControlsManager();
            propWindow = propWin;
        }

        /// <summary>
        /// Returns the unique istance of this class
        /// </summary>
        /// <returns></returns>
        public static SelectedControlsManager GetManager(){
            return man;
        }

        /// <summary>
        /// Gets selected controls
        /// </summary>
        /// <returns>array of selected skin elements</returns>
        public SkinControl[] getSelectedControls()
        {
            XmlElementPropertiesList[] list = controls.ToArray();
            SkinControl[] skinControl = new SkinControl[list.Length];
            for (int i = 0; i < list.Length; i++)
            {
                skinControl[i] = list[i].GetSkinControl();
            }
            return skinControl;

        }

        /// <summary>
        /// Change the selecetd project
        /// </summary>
        /// <param name="project">new ISkinDisplay with element of current project</param>
        public static void changeSelectedProject(ISkinDisplay screen)
        {
            display = screen;
        }

        /// <summary>
        /// Adds a control to selected controls list
        /// </summary>
        /// <param name="sc">just selected control</param>
        public void add(SkinControl sc){
            XmlElementPropertiesList list = new XmlElementPropertiesList(sc);
            //create a list that interescts all properties of selected controls
            controls.Add(list);
            ChangedSelection(list);
            sc.Selected = true;
        }

        /// <summary>
        /// Removes all controls from selected controls list
        /// </summary>
        public void removeAll(){

            foreach(XmlElementPropertiesList p in controls)
            {
                p.GetSkinControl().Selected = false;
                
            }
            controls.Clear();
        }

        /// <summary>
        /// brings to back the selected element so user can
        /// view element under it
        /// </summary>
        public void SendToBack()
        {
            if (controls.Count > 0) controls[0].GetSkinControl().SendToBack();
        }

        /// <summary>
        /// Change property value of the selected control/s
        /// </summary>
        /// <param name="prop">Property with new value</param>
        /// <remarks>raised ChangedProperty event for each selected controls</remarks>
        public void changePropertyValue(XmlElementProperty prop)
        {
            if (controls.Count == 0) return;
            foreach (XmlElementPropertiesList pl in controls)
            {
                try
                {
                    pl.ChangePropertyValue(prop.Name, prop.Value);
                    pl.GetSkinControl().ChangeElementProperty(prop);
                    if (ChangedProperty != null) ChangedProperty(pl.GetSkinControl(), prop);
                    pl.GetSkinControl().DrawControl();
                }
                catch (Exception ex) { }
                /*try
                {
                    ChangedProperty(pl.GetSkinControl(), prop);
                }
                catch (Exception ex) { }*/
            }
            //reload property list with property of last item
            ChangedSelection(controls[controls.Count - 1]);
            
        }


        public void Mouse_Move(object sender, MouseEventArgs mea)
        /*Moves e generic control in the sking panel*/
        {
            SkinControl c = (SkinControl)sender;
            if (c.Selected) c.Cursor = Cursors.SizeAll; else c.Cursor = Cursors.Default;
            if (moving)
            {
                c.Location = new Point(mea.X + c.Left - intDownX, mea.Y + c.Top - intDownY);
                propWindow.updatePropertyValue("X", c.Location.X);
                propWindow.updatePropertyValue("Y", c.Location.Y);
                //c.DrawControl();
            }
        }

        public void Mouse_Down(object sender, MouseEventArgs mea)
        /*Selects and preapares to move a single control in the skin panel*/
        {
            
            if (mea.Button == MouseButtons.Left)
            {
                SkinControl c = (SkinControl)sender;
                moving = true;
                if (Panel.ModifierKeys != Keys.Shift) { removeAll(); }
                add(c);
                intDownX = mea.X;
                intDownY = mea.Y;
            }
        }

        public void Mouse_Up(object sender, MouseEventArgs mea)
        /*release cToMove to be moved*/
        {
            
            if (mea.Button == MouseButtons.Left)
            {
                SkinControl c = (SkinControl)sender;
                rlTodayXmlElement el = c.SkinElement;
                el.X = c.Location.X;
                el.Y = c.Location.Y;
                moving = false;
                intDownX = -1;
                intDownY = -1;
            }
        }

        public void Key_Down(object sender, KeyEventArgs k)
        {
            SkinControl c = (SkinControl)sender;

            switch (k.KeyCode)
            {
                case Keys.Left:
                    c.Left -= 1;
                    propWindow.updatePropertyValue("X", c.Location);
                    break;
                case Keys.Right:
                    c.Left += 1;
                    propWindow.updatePropertyValue("X", c.Location);
                    break;
                case Keys.Up:
                    c.Top -= 1;
                    propWindow.updatePropertyValue("Y", c.Location);
                    break;
                case Keys.Down:
                    c.Top += 1;
                    propWindow.updatePropertyValue("Y", c.Location);
                    break;
            }/*end switch*/
        }


        /***********************************
         * PRIVATE MEMBERS
         * ********************************/

        
    }//end class
}//end namespace
